////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copyright (c) 2009 - 2010 RacoonStudios
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy of this
/// software and associated documentation files (the "Software"), to deal in the Software
/// without restriction, including without limitation the rights to use, copy, modify, merge,
/// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
/// to whom the Software is furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all copies or
/// substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
/// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
/// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
/// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
/// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/// DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once
#ifndef rtti_h__
#define rtti_h__

#include "core/types.h"
#include "helper/string.h"
#include "helper/fcc.h"
#include "core/factory.h"


namespace Core
{
	class ReferenceCount;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \class	Rtti
	///
	/// \brief	This Rtti (Runtime type information) is just like all the other
	///			Rtti's. It provides some information about the object itself 
	///			its parent and the size it contains within the memory.
	///
	///			I don't included an rtti object for multiple inheritance objects
	///			because I really can't realize in which situation you will use
	///			this type of construction. Nevertheless it's not a good design issue
	///			and leads to problems.
	///			If you really want to use this type it's over to you. Maybe with enough
	///			response to this I will include an alternative Rtti which will include
	///			multiple inheritance.
	///
	///	\todo	Add last documentation!
	///
	/// \author	khaos
	/// \date	21.12.2009
	////////////////////////////////////////////////////////////////////////////////////////////////////
	class Rtti
	{
		public:

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \typedef	ReferenceCount* (*Creator)()
			///
			/// \brief	.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			typedef ReferenceCount* (*Creator)();

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	Rtti(const char * name, 
			///			 const Helper::FCC & fcc, 
			///			 Creator creatorFnc, 
			///			 Rtti * parent,
			/// 		 tSize instSize)
			///
			/// \brief	Constructor. 
			///
			/// \author	Markus
			/// \date	12.02.2010
			///
			/// \param	[in]	name			The name. 
			/// \param	[in]	fcc				The fcc. 
			/// \param	[in]	creatorFnc		The creator fnc. 
			/// \param  [in]	parent			If non-null, the parent. 
			/// \param	[in]	instSize		Size of the instance. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			Rtti(const char * name, const Helper::FCC & fcc, Creator creatorFnc, Rtti * parent, tSize instSize);




			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	bool operator== (const Rtti & rhs) const
			///
			/// \brief	Equality operator. 
			///
			/// \author	khaos
			/// \date	21.12.2009
			///
			/// \param	[in]	rhs	The right hand side object. 
			///
			/// \return	True if both are the equal, otherwise false.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			bool operator == (const Rtti & rhs) const;

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	bool operator!= (const Rtti & rhs) const
			///
			/// \brief	Inequality operator. 
			///
			/// \author	khaos
			/// \date	21.12.2009
			///
			/// \param	[in]	rhs	The right hand side object. 
			///
			/// \return	True if both are inequal, otherwise false.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			bool operator != (const Rtti & rhs) const;




			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	const Helper::String & GetName() const
			///
			/// \brief	Returns the name of the class.
			///
			/// \author	khaos
			/// \date	21.12.2009
			///
			/// \return	The name. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			const Helper::String & GetName() const;

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	const Helper::FCC GetFCC() const
			///
			/// \brief	Returns the FCC of the class.
			///
			/// \author	khaos
			/// \date	21.12.2009
			///
			/// \return	The fcc. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			const Helper::FCC GetFCC() const;

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	const Rtti * GetParent() const
			///
			/// \brief	Returns the parent class of this one if there is any.
			///
			/// \author	khaos
			/// \date	21.12.2009
			///
			/// \return	Pointer to parent RTTI if there is one, otherwise NULL.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			const Rtti * GetParent() const;

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	ReferenceCount * Create() const
			///
			/// \brief	Creates an Intance of this object.
			///
			/// \author	Khaos
			/// \date	03.01.2010
			///
			/// \return	Returns a pointer to an instance of this class.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			ReferenceCount * Create() const;




			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	bool DerivesFrom(const Rtti & other) const
			///
			/// \brief	Determines if the specified class through its Rtti derives from this one.
			///
			/// \author	khaos
			/// \date	21.12.2009
			///
			/// \param	[in]	other	The other class. 
			///
			/// \return	True if the specified class derives from this one, otherwise false.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			bool DerivesFrom(const Rtti & other) const;

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	bool DerivesFrom(const Helper::String & other) const
			///
			/// \brief	Determines if the specified class through its name derives from this one.
			///
			/// \author	khaos
			/// \date	21.12.2009
			///
			/// \param	[in]	other	The other class. 
			///
			/// \return	True if the specified class derives from this one, otherwise false.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			bool DerivesFrom(const Helper::String & other) const;

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	bool DerivesFrom(const Helper::FCC & other) const
			///
			/// \brief	Determines if the specified class through its FCC derives from this one.
			///
			/// \author	khaos
			/// \date	21.12.2009
			///
			/// \param	[in]	other	The other class. 
			///
			/// \return	True if the specified class derives from this one, otherwise false.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			bool DerivesFrom(const Helper::FCC & other) const;





			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	void * AllocInstanceMemory()
			///
			/// \brief	Allocate memory for this class.
			///
			/// \author	Markus
			/// \date	12.02.2010
			///
			/// \return	null if it fails, else. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			void * AllocInstanceMemory();

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	void FreeInstanceMemory(void * ptr)
			///
			/// \brief	Frees the previously allocated memory.
			///
			/// \author	Markus
			/// \date	12.02.2010
			///
			/// \param	[in]	ptr	The instance we want to delete.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			void FreeInstanceMemory(void * ptr);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	tSize GetInstanceSize() const
			///
			/// \brief	Return the instance size. 
			///
			/// \author	Markus
			/// \date	12.02.2010
			///
			/// \return	The instance size. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			tSize GetInstanceSize() const;

		protected:

		private:

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	protected: private: Rtti()
			///
			/// \brief	Constructor.
			///
			/// \author	khaos
			/// \date	21.12.2009
			////////////////////////////////////////////////////////////////////////////////////////////////////
			Rtti();



			const Rtti * m_parent;

			Helper::String m_typeName;
			const Helper::FCC m_typeFCC;
			const Creator creator;

			tSize m_instSize;

	};




#define RE_DeclareClass(type) \
	public: \
		void * operator new(size_t size) \
		{ \
			return RTTI.AllocInstanceMemory(); \
		}; \
		void operator delete(void * ptr) \
		{ \
			RTTI.FreeInstanceMemory(ptr); \
		}; \
		static Core::Rtti RTTI; \
		static Core::ReferenceCount * FactoryCreator(); \
		static type * Create(); \
		static bool RegisterWithFactory(); \
		virtual Core::Rtti * GetRtti() const; \
	private:

#define RE_ImplementClass(fcc,type,parent) \
	Core::Rtti type::RTTI(#type, fcc, type::FactoryCreator, &parent::RTTI, sizeof(type)); \
	Core::Rtti * type::GetRtti() const { return &this->RTTI; } \
	Core::ReferenceCount * type::FactoryCreator() { return type::Create(); } \
	type * type::Create() \
	{ \
		return r_new(type); \
	} \
	bool type::RegisterWithFactory() \
	{ \
		if(!Core::Factory::Instance()->ClassExists(#type)) \
		{ \
			Core::Factory::Instance()->Register(&type::RTTI, #type, fcc); \
		} \
	return true; \
	}

#define RE_ImplementRootClass(fcc,type) \
	Core::Rtti type::RTTI(#type, fcc, type::FactoryCreator, 0, sizeof(type)); \
	Core::Rtti * type::GetRtti() const { return &this->RTTI; } \
	Core::ReferenceCount * type::FactoryCreator() { return type::Create(); } \
	type * type::Create() \
	{ \
		return r_new(type); \
	} \
	bool type::RegisterWithFactory() \
	{ \
		if(!Core::Factory::Instance()->ClassExists(#type)) \
		{ \
			Core::Factory::Instance()->Register(&type::RTTI, #type, fcc); \
		} \
	return true; \
	}


}

#endif // rtti_h__